package org.spiderflow.core.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.MessageSourceResolvable;
import org.springframework.core.ResolvableType;
import org.springframework.core.env.Environment;
import org.springframework.core.io.Resource;

import java.io.IOException;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Locale;
import java.util.Map;

/**
 * @author 张中海
 */

public class SpringUtils {
    private static final Logger logger = LoggerFactory.getLogger(SpringUtils.class);
    private static final String APPLICATION_CONTEXT_GET_BEAN_ERROR = "applicationContext.getBean error";
    private static ApplicationContext applicationContext;

    public static void setApplicationContext(ApplicationContext context) {
        applicationContext = context;
    }


    public static Object getBeanOrNull(String name) {
        try {
            return applicationContext.getBean(name);
        } catch (BeansException e) {
            logger.error(APPLICATION_CONTEXT_GET_BEAN_ERROR, e);
            return null;
        }
    }

    public static <T> T getBeanOrNull(String name, Class<T> requiredType) {
        try {
            return applicationContext.getBean(name, requiredType);
        } catch (BeansException e) {
            logger.error(APPLICATION_CONTEXT_GET_BEAN_ERROR, e);
            return null;
        }
    }

    public static Object getBeanOrNull(String name, Object... args) {
        try {
            return applicationContext.getBean(name, args);
        } catch (BeansException e) {
            logger.error(APPLICATION_CONTEXT_GET_BEAN_ERROR, e);
            return null;
        }
    }

    public static <T> T getBeanOrNull(Class<T> requiredType) {
        try {
            return applicationContext.getBean(requiredType);
        } catch (BeansException e) {
            logger.error(APPLICATION_CONTEXT_GET_BEAN_ERROR, e);
            return null;
        }
    }

    public static <T> T getBeanOrNull(Class<T> requiredType, Object... args) {
        try {
            return applicationContext.getBean(requiredType, args);
        } catch (BeansException e) {
            logger.error(APPLICATION_CONTEXT_GET_BEAN_ERROR, e);
            return null;
        }
    }

    public static Class<?> getTypeOrNull(String name) {
        try {
            return applicationContext.getType(name);
        } catch (NoSuchBeanDefinitionException e) {
            logger.error(APPLICATION_CONTEXT_GET_BEAN_ERROR, e);
            return null;
        }
    }

    //delegate ApplicationContext methods
    public static String getId() {
        return applicationContext.getId();
    }

    public static String getApplicationName() {
        return applicationContext.getApplicationName();
    }

    public static String getDisplayName() {
        return applicationContext.getDisplayName();
    }

    public static long getStartupDate() {
        return applicationContext.getStartupDate();
    }

    public static ApplicationContext getParent() {
        return applicationContext.getParent();
    }

    public static AutowireCapableBeanFactory getAutowireCapableBeanFactory() {
        return applicationContext.getAutowireCapableBeanFactory();
    }

    public static Environment getEnvironment() {
        return applicationContext.getEnvironment();
    }

    public static boolean containsBeanDefinition(String beanName) {
        return applicationContext.containsBeanDefinition(beanName);
    }

    public static int getBeanDefinitionCount() {
        return applicationContext.getBeanDefinitionCount();
    }

    public static String[] getBeanDefinitionNames() {
        return applicationContext.getBeanDefinitionNames();
    }

    public static String[] getBeanNamesForType(ResolvableType type) {
        return applicationContext.getBeanNamesForType(type);
    }

    public static String[] getBeanNamesForType(Class<?> type) {
        return applicationContext.getBeanNamesForType(type);
    }

    public static String[] getBeanNamesForType(Class<?> type, boolean includeNonSingletons, boolean allowEagerInit) {
        return applicationContext.getBeanNamesForType(type, includeNonSingletons, allowEagerInit);
    }

    public static <T> Map<String, T> getBeansOfType(Class<T> type) {
        return applicationContext.getBeansOfType(type);
    }

    public static <T> Collection<T> getBeansCollectionOfType(Class<T> type) {
        return applicationContext.getBeansOfType(type).values();
    }

    public static <T> Map<String, T> getBeansOfType(Class<T> type, boolean includeNonSingletons, boolean allowEagerInit) {
        return applicationContext.getBeansOfType(type, includeNonSingletons, allowEagerInit);
    }

    public static String[] getBeanNamesForAnnotation(Class<? extends Annotation> annotationType) {
        return applicationContext.getBeanNamesForAnnotation(annotationType);
    }

    public static Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annotationType) {
        return applicationContext.getBeansWithAnnotation(annotationType);
    }

    public static <A extends Annotation> A findAnnotationOnBean(String beanName, Class<A> annotationType) {
        return applicationContext.findAnnotationOnBean(beanName, annotationType);
    }

    public static Object getBean(String name) {
        return applicationContext.getBean(name);
    }

    public static <T> T getBean(String name, Class<T> requiredType) {
        return applicationContext.getBean(name, requiredType);
    }

    public static Object getBean(String name, Object... args) {
        return applicationContext.getBean(name, args);
    }

    public static <T> T getBean(Class<T> requiredType) {
        return applicationContext.getBean(requiredType);
    }

    public static <T> T getBean(Class<T> requiredType, Object... args) {
        return applicationContext.getBean(requiredType, args);
    }

    public static boolean containsBean(String name) {
        return applicationContext.containsBean(name);
    }

    public static boolean isSingleton(String name) {
        return applicationContext.isSingleton(name);
    }

    public static boolean isPrototype(String name) {
        return applicationContext.isPrototype(name);
    }

    public static boolean isTypeMatch(String name, ResolvableType typeToMatch) {
        return applicationContext.isTypeMatch(name, typeToMatch);
    }

    public static boolean isTypeMatch(String name, Class<?> typeToMatch) {
        return applicationContext.isTypeMatch(name, typeToMatch);
    }

    public static Class<?> getType(String name) {
        return applicationContext.getType(name);
    }

    public static String[] getAliases(String name) {
        return applicationContext.getAliases(name);
    }

    public static BeanFactory getParentBeanFactory() {
        return applicationContext.getParentBeanFactory();
    }

    public static boolean containsLocalBean(String name) {
        return applicationContext.containsLocalBean(name);
    }

    public static String getMessage(String code, Object[] args, String defaultMessage, Locale locale) {
        return applicationContext.getMessage(code, args, defaultMessage, locale);
    }

    public static String getMessage(String code, Object[] args, Locale locale) {
        return applicationContext.getMessage(code, args, locale);
    }

    public static String getMessage(MessageSourceResolvable resolvable, Locale locale) {
        return applicationContext.getMessage(resolvable, locale);
    }


    public static void publishEvent(ApplicationEvent event) {
        applicationContext.publishEvent(event);
    }

    public static void publishEvent(Object event) {
        applicationContext.publishEvent(event);
    }

    public static Resource[] getResources(String locationPattern) throws IOException {
        return applicationContext.getResources(locationPattern);
    }

    public static Resource getResource(String location) {
        return applicationContext.getResource(location);
    }

    public static ClassLoader getClassLoader() {
        return applicationContext.getClassLoader();
    }

    private SpringUtils() {
    }
}